package ejb.managerbeans;

import java.sql.Time;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;

import ejb.dto.EscursioneDTO;
import ejb.dto.HotelDTO;
import ejb.dto.ProdottoBaseDTO;
import ejb.dto.UserDTO;
import ejb.dto.VoloDTO;
import ejb.entities.Basicproduct;
import ejb.entities.Escursion;
import ejb.entities.Flight;
import ejb.entities.Group;
import ejb.entities.Hotel;
import ejb.entities.User;
import ejb.entities.UserBasicproduct;
import ejb.utility.ConvertDTO;

/**
 * Session Bean implementation class ProdottoManagerBean
 */
@Stateless
public class ProdottoManagerBean implements ProdottoManagerBeanLocal {
	@PersistenceContext
	private EntityManager em;

	@Resource
	private EJBContext context;

	/**
	 * Default constructor.
	 */
	public ProdottoManagerBean() {
		// TODO Auto-generated constructor stub
	}

	@Override
	@RolesAllowed({ Group.ADMIN })
	public void save(ProdottoBaseDTO pb, Object sottoPacchetto) {
		Basicproduct newPb = new Basicproduct(pb);
		em.persist(newPb);
		User user = em.find(User.class, context.getCallerPrincipal().getName());
		newPb.setUser(user);
		user.addBasicproduct(newPb);

		if (sottoPacchetto instanceof EscursioneDTO) {
			Escursion escursion = new Escursion((EscursioneDTO) sottoPacchetto);
			newPb.setEscursion(escursion);
			escursion.setUscursionid(newPb.getBasicproductid());
			escursion.setBasicproduct(newPb);
		} else if (sottoPacchetto instanceof HotelDTO) {
			Hotel hotel = new Hotel((HotelDTO) sottoPacchetto);
			newPb.setHotel(hotel);
			hotel.setHotelid(newPb.getBasicproductid());
			hotel.setBasicproduct(newPb);
		} else {
			Flight flight = new Flight((VoloDTO) sottoPacchetto);
			newPb.setFlight(flight);
			flight.setFlightId(newPb.getBasicproductid());
			flight.setBasicproduct(newPb);
		}
	}

	@Override
	@RolesAllowed({ Group.ADMIN })
	public void update(ProdottoBaseDTO pb, Object sottoPacchetto) {
		Basicproduct oldpb = find(pb.getId());
		if (oldpb != null) {
			Basicproduct newpb = em.merge(oldpb);
			newpb.setStartdate(pb.getDataInizio());
			newpb.setEnddate(pb.getDataFine());
			newpb.setPlaces(pb.getNposti());
			newpb.setPrice(pb.getPrezzo());
			User user = em.find(User.class, context.getCallerPrincipal()
					.getName());
			newpb.setUser(user);

			if (sottoPacchetto instanceof EscursioneDTO) {
				Escursion oldescursion = findEscursion(pb.getId());
				Escursion escursion = em.merge(oldescursion);
				escursion.setCity(((EscursioneDTO) sottoPacchetto).getCitta());
				escursion.setStarthour(new Time(
						((EscursioneDTO) sottoPacchetto).getOraInizio()
								.getTime()));
			} else if (sottoPacchetto instanceof HotelDTO) {
				Hotel oldhotel = findHotel(pb.getId());
				Hotel hotel = em.merge(oldhotel);
				hotel.setCity(((HotelDTO) sottoPacchetto).getCitta());
				hotel.setName(((HotelDTO) sottoPacchetto).getNome());
				hotel.setStars(((HotelDTO) sottoPacchetto).getStelle());
			} else {
				Flight oldflight = findFlight(pb.getId());
				Flight flight = em.merge(oldflight);
				flight.setArrival(((VoloDTO) sottoPacchetto).getCitta_arrivo());
				flight.setDeparture(((VoloDTO) sottoPacchetto)
						.getCitta_partenza());
				flight.setCompany(((VoloDTO) sottoPacchetto).getCompagnia());
				flight.setModel(((VoloDTO) sottoPacchetto).getAereo());
			}
		}
	}

	@Override
	public Object dtoById(String typeDTO, int id) {
		Basicproduct bp = find(id);
		if (typeDTO.equals("escursione"))
			return ConvertDTO.convertToEscursioneDTO(bp.getEscursion());
		else if (typeDTO.equals("hotel"))
			return ConvertDTO.convertToHotelDTO(bp.getHotel());
		if (typeDTO.equals("volo"))
			return ConvertDTO.convertToVoloDTO(bp.getFlight());
		return null;
	}

	public List<Basicproduct> getAllPb() {
		return em.createNamedQuery(Basicproduct.FIND_ALL, Basicproduct.class)
				.getResultList();
	}

	public Basicproduct find(int id) {
		return em.find(Basicproduct.class, id);
	}

	@Override
	@RolesAllowed({ Group.ADMIN })
	public void remove(int id) {
		em.remove(find(id));
	}

	@Override
	public List<ProdottoBaseDTO> getAllPbDTO() {
		List<ProdottoBaseDTO> pbDTO = new ArrayList<ProdottoBaseDTO>();
		List<Basicproduct> pb = getAllPb();

		for (Basicproduct p : pb)
			pbDTO.add(ConvertDTO.convertToDTOPb(p));

		return pbDTO;
	}

	public void boughtBasicProduct(ProdottoBaseDTO pb, UserDTO userDTO) {

		// Aggiungi il prodotto base acquistato alla lista dei prodotti
		// acquistati dall'utente
		Basicproduct bp = em
				.createNamedQuery(Basicproduct.FIND_BYID, Basicproduct.class)
				.setParameter("id", pb.getId()).getSingleResult();

		User newUser;

		/** Caso in cui l'utente e' loggato */
		if (userDTO.getEmail() == null) {
			newUser = em.find(User.class, context.getCallerPrincipal()
					.getName());
		} else {
			/** Utente non loggato */

			List<Basicproduct> bpList = new ArrayList<Basicproduct>();

			try {
				/**
				 * Utente non loggato ma gia' registrato e riconosciuto
				 * dall'email
				 */
				newUser = em.createNamedQuery(User.FINDBYID, User.class)
						.setParameter("id", userDTO.getEmail())
						.getSingleResult();
			} catch (NoResultException nre) {
				/** Nuovo utente */
				List<Group> groups = new ArrayList<Group>();

				newUser = new User();
				newUser.setUserid(userDTO.getEmail());
				newUser.setName(userDTO.getFirstName());
				newUser.setSurname(userDTO.getLastName());

				// cerca l'oggetto Group da inserire nella lista dei gruppi
				// degli
				// utentie associo all'utente
				Group g = em.createNamedQuery(Group.FINDBYNAME, Group.class)
						.setParameter("id", "VISITORS").getSingleResult();
				groups.add(g);
				newUser.setGroups(groups);
				g.getUsers().add(newUser);

				newUser.setBasicproducts(bpList);

				// non necessario associare giftlist poiche' si tratta di un
				// visitatore
				em.persist(newUser);

			}
		}

		newUser.getBasicproducts().add(bp);

		UserBasicproduct newUBP = new UserBasicproduct();

		newUBP.setDate(new Date());
		newUBP.setBasicproduct(bp);
		newUBP.setUser(newUser);

		// Associa al prodottobase la relazione con l'utente
		bp.getUserBasicproducts().add(newUBP);

		em.persist(newUBP);

//		System.out.println("inserito in user_basicproduct:"
//				+ newUBP.getUser().getUserid().toString());

	}

	public Escursion findEscursion(int id) {
		return em.find(Escursion.class, id);
	}

	public Hotel findHotel(int id) {
		return em.find(Hotel.class, id);
	}

	public Flight findFlight(int id) {
		return em.find(Flight.class, id);
	}

	@Override
	public ProdottoBaseDTO getPBDTOByID(int idPB) {
		return ConvertDTO.convertToDTOPb((Basicproduct) em.find(
				Basicproduct.class, idPB));
	}

}
